package com.after.saas.common.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import com.google.common.base.Utf8;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.SecureRandom;

/**
 * @version 1.0
 * @date 2021-07-15
 */
public final class EncodeUtil {

    private static Logger log = LoggerFactory.getLogger(EncodeUtil.class);
    private static final String HEX_STRING = "0123456789abcdef";
    private static final char[] HEX_DIGITS = HEX_STRING.toCharArray();

    public static String base64DecodeStr(String str) {
        return encodeBytes(Base64.decode(str), "");
    }

    public static byte[] base64Decode(String str) {
        return Base64.decode(str);
    }

    public static String base64EncodeStr(String str) {
        return Base64.decodeStrGbk(str);
    }

    public static String base64Encode(byte[] bytes) {
        return Base64.encode(bytes);
    }

    public static String base64EncodeStrForUrl(String str) {
        return urlEncodeStr(base64EncodeStr(str));
    }

    public static String base64DecodeStrFromUrl(String str) {
        return base64DecodeStr(urlDecodeStr(str));
    }

    public static String toHex(byte[] bytes) {
        StringBuilder ret = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
        }
        return ret.toString();
    }

    public static byte[] fromHex(String str) {
        if (StrUtil.isBlank(str)) {
            return null;
        }
        str = str.toLowerCase();
        int len = str.length() / 2;
        byte[] bytes = new byte[len];
        char[] hexChars = str.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            bytes[i] = (byte) (Character.getNumericValue(hexChars[pos]) << 4
                    | Character.getNumericValue(hexChars[pos + 1]));
        }
        return bytes;
    }

    /**
     * 字符串编码工具,用来转换url中的乱码情况
     *
     * @param str
     * @return
     */
    public static String encodeStr(String str) {
        try {
            return new String(str.getBytes("ISO_8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String encodeBytes(byte[] bytes, String defVal) {
        if (bytes == null) {
            return defVal;
        }
        String str = null;
        try {
            str = new String(bytes, "utf-8");
        } catch (UnsupportedEncodingException e) {
            str = defVal;
        }
        return str;
    }

    public static String encodeBytesWithURLEncode(byte[] bytes, String defVal) {
        String str = encodeBytes(bytes, defVal);
        if (StrUtil.isNotBlank(str)) {
            try {
                str = URLEncoder.encode(str, "utf-8");
            } catch (UnsupportedEncodingException e) {
                str = defVal;
            }
        }
        return str;
    }

    public static byte[] decodeBytesObj(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof String) {
            return decodeBytes((String) obj);
        }
        return decodeBytes(obj.toString());
    }

    public static byte[] decodeBytes(String str) {
        byte[] bytes = null;
        if (StrUtil.isNotBlank(str)) {
            try {
                bytes = str.getBytes("utf-8");
            } catch (UnsupportedEncodingException e) {
                bytes = null;
            }
        }
        return bytes;
    }

    public static int utf8EncodedLength(String str) {
        if (StrUtil.isBlank(str)) {
            return 0;
        }
        return Utf8.encodedLength(str);
    }

    public static String getEncryptionToken(String token) {
        for (int i = 0; i < 6; i++) {
            token = base64EncodeStr(token);
        }
        return token;
    }

    public static String getDecryptToken(String encryptionToken) {
        for (int i = 0; i < 6; i++) {
            encryptionToken = base64DecodeStr(encryptionToken);
        }
        return encryptionToken;
    }

    public static String noHtml(String s) {
        if (StrUtil.isBlank(s)) {
            return "";
        }
        return s.replaceAll("<[.[^<]]*>", "");
    }

    public static String transHtml(String s) {
        if (StrUtil.isBlank(s)) {
            return "";
        }
        return s.replace("<", "&lt;").replace(">", "&gt;");
    }

    public static boolean hasSqlWildcard(String str) {
        if (str != null) {
            return !StrUtil.equals(str, str.replaceAll("[*%]*", ""));
        }
        return false;
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     * <p>
     * 转义后的URL可作为URL中的参数
     */
    public static String urlDecodeStr(String str) {
        if (StrUtil.isNotBlank(str)) {
            try {
                str = URLDecoder.decode(str, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            str = encodeStr(str);
        }
        return str;
    }

    /**
     * URL 解码, Encode默认为UTF-8. 转义后的URL可作为URL中的参数
     */
    public static String urlEncodeStr(String str) {
        if (StrUtil.isNotBlank(str)) {
            try {
                str = URLEncoder.encode(str, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return str;
    }

    public static String strUrlPlus(String p) {
        if (StrUtil.isNotBlank(p)) {
            if (StrUtil.contains(p, '_')) {
                p = StrUtil.replace(p, "_", "+");
            }
        }
        return p;
    }

    public static String encrypt(String content, String key) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(key.getBytes());
            kgen.init(128, secureRandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            byte[] result = cipher.doFinal(content.getBytes("utf-8"));
            return Base64.encode(result);
        } catch (Exception e) {
            log.error("加密异常", e);
        }
        return null;
    }

    public static String decrypt(String content, String key) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(key.getBytes());
            kgen.init(128, secureRandom);
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            byte[] byteContent = Base64.decode(content);
            byte[] result = cipher.doFinal(byteContent);
            return new String(result, "utf-8");
        } catch (Exception e) {
            log.error("解密异常", e);
        }
        return null;
    }

    public static void main(String[] args) {
        String str1 = "user_id12_email3";
        String str2 = "user_id12_email3";
        String cameCase = StrUtil.toCamelCase(str1);
        System.out.println(StrUtil.toCamelCase(str2) + "\t" + cameCase);
        System.out.println(String.format("cameCase:%s,underLiner:%s", cameCase, StrUtil.toUnderlineCase(str2)));
        String key = "test";
        String ecodeStr = "Tm+os9a7FLecDRljxX2gqg==";
        System.out.println(strUrlPlus(str1));
        System.out.println(encrypt(str1, key));
        System.out.println(decrypt(ecodeStr, key));
    }
}
